﻿#include <QTimer>
#include "JZGLScene.h"
#include "JZGLView.h"

JZGLScene::ItemData::ItemData()
{
    changed = false;
}

void JZGLScene::ItemData::clear()
{
    meshVertex.clear();
    meshIndex.clear();
    lineVertex.clear();
    lineIndex.clear();
}

//JZGLScene
JZGLScene::JZGLScene(QObject* parent )
    :QObject(parent)
{
    m_updateTimer = new QTimer(this);
    m_updateTimer->setSingleShot(true);
    connect(m_updateTimer, &QTimer::timeout, this, &JZGLScene::onUpdate);
}

JZGLScene::~JZGLScene()
{
    qDeleteAll(m_items);
    m_items.clear();
}

QList<JZGLView*> JZGLScene::views()
{
    return m_views;
}

void JZGLScene::addView(JZGLView* view)
{
    m_views.push_back(view);
}

void JZGLScene::removeView(JZGLView* view)
{
    m_views.removeAll(view);
}

void JZGLScene::addItem(JZGLItem* item)
{
    Q_ASSERT(!item->scene());
    item->setScene(this);
    m_items.push_back(item);
    m_itemData.insert(item, ItemData());
    updateItem(item);
}

void JZGLScene::removeItem(JZGLItem* item)
{
    m_itemData.remove(item);
    m_items.removeAll(item);
    delete item;
    update();
}

void JZGLScene::clear()
{
    qDeleteAll(m_items);
    m_items.clear();
    update();
}

JZGLTriangleItem* JZGLScene::addTriangle(QVector3D p1, QVector3D p2, QVector3D p3, QColor c)
{
    QVector3D pos;
    QVector<QVector3D> local_list;
    JZGLItem::worldToLocal({ p1,p2,p3 }, pos, local_list);

    QVector<VertexData> vertex_list;
    for (int i = 0; i < local_list.size(); i++)
    {
        VertexData v;
        v.pos = local_list[i];
        v.color = c;
    }

    JZGLTriangleItem* tri = new JZGLTriangleItem();
    tri->setTriangle(vertex_list[0], vertex_list[1], vertex_list[2]);
    addItem(tri);
    return tri;
}

// 修改后的addBox函数实现，根据传入的8个顶点坐标生成相应的顶点和索引数据并加载到缓冲
JZGLRectItem* JZGLScene::addRect(QVector3D center, float w, float h, QColor c)
{
    JZGLRectItem* item = new JZGLRectItem();
    item->setPosition(center);
    item->setRect(w, h, c);
    addItem(item);
    return item;
}

JZGLBoxItem* JZGLScene::addBox(QVector3D center, float w, float h, float depth, QColor c)
{
    JZGLBoxItem* item = new JZGLBoxItem();
    item->setPosition(center);
    item->setBox(w, h, depth, c);
    addItem(item);
    return item;
}

JZGLLineItem* JZGLScene::addLine(QVector3D p1, QVector3D p2, QColor c)
{
    QVector3D pos;
    QVector<QVector3D> local_list;
    JZGLItem::worldToLocal({ p1,p2 }, pos, local_list);

    QVector<VertexData> vertex_list;
    for (int i = 0; i < local_list.size(); i++)
    {
        VertexData v;
        v.pos = local_list[i];
        v.color = c;
        vertex_list.push_back(v);
    }

    JZGLLineItem* item = new JZGLLineItem();
    item->setPosition(pos);
    item->setLine(vertex_list[0], vertex_list[1]);
    addItem(item);
    return item;
}

JZGLTextItem* JZGLScene::addText(const QString& text, QColor c)
{
    JZGLTextItem* item = new JZGLTextItem();
    item->setText(text);
    item->setColor(c);
    addItem(item);
    return item;
}

void JZGLScene::addVertex(int type,JZGLItem* item, const QVector<VertexData>& pt_list, const QVector<int>& index_list)
{
    QVector<VertexData> *pVertex = nullptr;
    QVector<uint32_t> *pIndex = nullptr;

    QVector3D pos = item->position();
    QMatrix4x4 model = item->model();
    while (item->parent())
    {
        item = item->parent();
        model = item->model() * model;
        pos += item->position();
    }

    auto& d = m_itemData[item];
    if (type == 0)
    {
        pVertex = &d.lineVertex;
        pIndex = &d.lineIndex;
    }
    else
    {
        pVertex = &d.meshVertex;
        pIndex = &d.meshIndex;
    }

    int start = pVertex->size();
    for (int i = 0; i < pt_list.size(); i++)
    {
        pVertex->append(pt_list[i]);
        auto& vec = pVertex->back();
        vec.pos = model * vec.pos;
    }

    int vec_size = pt_list.size();
    for (int i = 0; i < index_list.size(); i++)
    {
        Q_ASSERT(index_list[i] >= 0 && index_list[i] < vec_size);
        pIndex->push_back(start + index_list[i]);
    }
}

void JZGLScene::addLineVertex(JZGLItem* item, const QVector<VertexData>& pt_list, const QVector<int>& index_list)
{
    addVertex(0, item, pt_list, index_list);
}

void JZGLScene::addMeshVertex(JZGLItem* item, const QVector<VertexData>& pt_list, const QVector<int>& index_list)
{
    addVertex(1, item, pt_list, index_list);
}

void JZGLScene::notifyItemChanged(JZGLItem* item)
{
    updateItem(item);
}

void JZGLScene::updateItem(JZGLItem* item)
{
    m_itemData[item].changed = true;
    update();
}

void JZGLScene::update()
{
    m_updateTimer->start();
}

void JZGLScene::onUpdate()
{
    auto it = m_itemData.begin();
    while (it != m_itemData.end())
    {
        if (it->changed)
        {
            it->clear();
            it.key()->updateBuffer();
            it->changed = false;
        }
        it++;
    }
    
    for (int i = 0; i < m_views.size(); i++)
        m_views[i]->updateItemBuffer();
}